/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { flatten } from '../../utils/array.js';
import { factory } from '../../utils/factory.js';
var name = 'mode';
var dependencies = ['typed', 'isNaN', 'isNumeric'];
export var createMode = /* #__PURE__ */factory(name, dependencies, _ref => {
  var {
    typed,
    isNaN,
    isNumeric
  } = _ref;

  /**
  * Computes the mode of a set of numbers or a list with values(numbers or characters).
  * If there are more than one modes, it returns a list of those values.
  *
  * Syntax:
  *
  *     math.mode(a, b, c, ...)
  *     math.mode(A)
  *
  * Examples:
  *
  *     math.mode(2, 1, 4, 3, 1)                            // returns [1]
  *     math.mode([1, 2.7, 3.2, 4, 2.7])                    // returns [2.7]
  *     math.mode(1, 4, 6, 1, 6)                             // returns [1, 6]
  *     math.mode('a','a','b','c')                           // returns ["a"]
  *     math.mode(1, 1.5, 'abc')                             // returns [1, 1.5, "abc"]
  *
  * See also:
  *
  *     median,
  *     mean
  *
  * @param {... *} args  A single matrix
  * @return {*} The mode of all values
  */
  return typed(name, {
    'Array | Matrix': _mode,
    '...': function _(args) {
      return _mode(args);
    }
  });
  /**
   * Calculates the mode in an 1-dimensional array
   * @param {Array} values
   * @return {Array} mode
   * @private
   */

  function _mode(values) {
    values = flatten(values.valueOf());
    var num = values.length;

    if (num === 0) {
      throw new Error('Cannot calculate mode of an empty array');
    }

    var count = {};
    var mode = [];
    var max = 0;

    for (var i = 0; i < values.length; i++) {
      var value = values[i];

      if (isNumeric(value) && isNaN(value)) {
        throw new Error('Cannot calculate mode of an array containing NaN values');
      }

      if (!(value in count)) {
        count[value] = 0;
      }

      count[value]++;

      if (count[value] === max) {
        mode.push(value);
      } else if (count[value] > max) {
        max = count[value];
        mode = [value];
      }
    }

    return mode;
  }
});